#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char gsm7[]={
     '@',   /* COMMERCIAL T */
     163,   /* POUND SIGN */
     36,   /* DOLLAR SIGN */
    165,   /* YEN SIGN */
    232,   /* LATIN SMALL LETTER E WITH GRAVE */
    233,   /* LATIN SMALL LETTER E WITH ACUTE */
    249,   /* LATIN SMALL LETTER U WITH GRAVE */
    236,   /* LATIN SMALL LETTER I WITH GRAVE */
    242,   /* LATIN SMALL LETTER O WITH GRAVE */
    199,   /* LATIN SMALL LETTER C WITH CEDILLA */
    10,   /* LINE FEED */
    216,   /* LATIN CAPITAL LETTER O WITH STROKE */
    248,   /* LATIN SMALL LETTER O WITH STROKE */
    13,   /* CARRIAGE RETURN */
    197,   /* LATIN CAPITAL LETTER A WITH RING ABOVE */
    229,   /* LATIN SMALL LETTER A WITH RING ABOVE */
    0,   /* GREEK CAPITAL LETTER DELTA */
    95,   /* LOW LINE */
    0,   /* GREEK CAPITAL LETTER PHI */
    0,   /* GREEK CAPITAL LETTER GAMMA */
    0,   /* GREEK CAPITAL LETTER LAMDA */
    0,   /* GREEK CAPITAL LETTER OMEGA */
    0,   /* GREEK CAPITAL LETTER PI */
    0,   /* GREEK CAPITAL LETTER PSI */
    0,   /* GREEK CAPITAL LETTER SIGMA */
    0,   /* GREEK CAPITAL LETTER THETA */
    0,   /* GREEK CAPITAL LETTER XI */
    27,   /* ESCAPE TO EXTENSION TABLE */
    198,   /* LATIN CAPITAL LETTER AE */
    230,   /* LATIN SMALL LETTER AE */
    223,   /* LATIN SMALL LETTER SHARP S (German) */
    201,   /* LATIN CAPITAL LETTER E WITH ACUTE */
    32,   /* SPACE */
    33,   /* EXCLAMATION MARK */
    34,   /* QUOTATION MARK */
    35,   /* NUMBER SIGN */
    164,   /* CURRENCY SIGN */
    37,   /* PERCENT SIGN */
    38,   /* AMPERSAND */
    39,   /* APOSTROPHE */
    40,   /* LEFT PARENTHESIS */
    41,   /* RIGHT PARENTHESIS */
    42,   /* ASTERISK */
    43,   /* PLUS SIGN */
    44,   /* COMMA */
    45,   /* HYPHEN-MINUS */
    46,   /* FULL STOP */
    47,   /* SOLIDUS */
    48,   /* DIGIT ZERO */
    49,   /* DIGIT ONE */
    50,   /* DIGIT TWO */
    51,   /* DIGIT THREE */
    52,   /* DIGIT FOUR */
    53,   /* DIGIT FIVE */
    54,   /* DIGIT SIX */
    55,   /* DIGIT SEVEN */
    56,   /* DIGIT EIGHT */
    57,   /* DIGIT NINE */
    58,   /* COLON */
    59,   /* SEMICOLON */
    60,   /* LESS-THAN SIGN */
    61,   /* EQUALS SIGN */
    62,   /* GREATER-THAN SIGN */
    63,   /* QUESTION MARK */
    161,   /* INVERTED EXCLAMATION MARK */
    65,   /* LATIN CAPITAL LETTER A */
    66,   /* LATIN CAPITAL LETTER B */
    67,   /* LATIN CAPITAL LETTER C */
    68,   /* LATIN CAPITAL LETTER D */
    69,   /* LATIN CAPITAL LETTER E */
    70,   /* LATIN CAPITAL LETTER F */
    71,   /* LATIN CAPITAL LETTER G */
    72,   /* LATIN CAPITAL LETTER H */
    73,   /* LATIN CAPITAL LETTER I */
    74,   /* LATIN CAPITAL LETTER J */
    75,   /* LATIN CAPITAL LETTER K */
    76,   /* LATIN CAPITAL LETTER L */
    77,   /* LATIN CAPITAL LETTER M */
    78,   /* LATIN CAPITAL LETTER N */
    79,   /* LATIN CAPITAL LETTER O */
    80,   /* LATIN CAPITAL LETTER P */
    81,   /* LATIN CAPITAL LETTER Q */
    82,   /* LATIN CAPITAL LETTER R */
    83,   /* LATIN CAPITAL LETTER S */
    84,   /* LATIN CAPITAL LETTER T */
    85,   /* LATIN CAPITAL LETTER U */
    86,   /* LATIN CAPITAL LETTER V */
    87,   /* LATIN CAPITAL LETTER W */
    88,   /* LATIN CAPITAL LETTER X */
    89,   /* LATIN CAPITAL LETTER Y */
    90,   /* LATIN CAPITAL LETTER Z */
    196,   /* LATIN CAPITAL LETTER A WITH DIAERESIS */
    214,   /* LATIN CAPITAL LETTER O WITH DIAERESIS */
    209,   /* LATIN CAPITAL LETTER N WITH TILDE */
    220,   /* LATIN CAPITAL LETTER U WITH DIAERESIS */
    167,   /* SECTION SIGN */
    191,   /* INVERTED QUESTION MARK */
    97,   /* LATIN SMALL LETTER A */
    98,   /* LATIN SMALL LETTER B */
    99,   /* LATIN SMALL LETTER C */
    100,   /* LATIN SMALL LETTER D */
    101,   /* LATIN SMALL LETTER E */
    102,   /* LATIN SMALL LETTER F */
    103,   /* LATIN SMALL LETTER G */
    104,   /* LATIN SMALL LETTER H */
    105,   /* LATIN SMALL LETTER I */
    106,   /* LATIN SMALL LETTER J */
    107,   /* LATIN SMALL LETTER K */
    108,   /* LATIN SMALL LETTER L */
    109,   /* LATIN SMALL LETTER M */
    110,   /* LATIN SMALL LETTER N */
    111,   /* LATIN SMALL LETTER O */
    112,   /* LATIN SMALL LETTER P */
    113,   /* LATIN SMALL LETTER Q */
    114,   /* LATIN SMALL LETTER R */
    115,   /* LATIN SMALL LETTER S */
    116,   /* LATIN SMALL LETTER T */
    117,   /* LATIN SMALL LETTER U */
    118,   /* LATIN SMALL LETTER V */
    119,   /* LATIN SMALL LETTER W */
    120,   /* LATIN SMALL LETTER X */
    121,   /* LATIN SMALL LETTER Y */
    122,   /* LATIN SMALL LETTER Z */
    228,   /* LATIN SMALL LETTER A WITH DIAERESIS */
    246,   /* LATIN SMALL LETTER O WITH DIAERESIS */
    241,   /* LATIN SMALL LETTER N WITH TILDE */
    252,   /* LATIN SMALL LETTER U WITH DIAERESIS */
    224    /* LATIN SMALL LETTER A WITH GRAVE */
};

static struct

{
   unsigned char   from;
   unsigned char   to;

} gsm_escape[]={ // prve je ascii znak, druhe je cislo znaku co ma nasledovat za escape znakom

    { 12, 10 },   /* FORM FEED */
    { '^', 20 },   /* CIRCUMFLEX ACCENT */
    { '{', 40 },   /* LEFT CURLY BRACKET */
    { '}', 41 },   /* RIGHT CURLY BRACKET */
    { '\\', 47 },   /* REVERSE SOLIDUS */
    { '[', 60 },   /* LEFT SQUARE BRACKET */
    { '~', 61 },   /* TILDE */
    { ']', 62 },   /* RIGHT SQUARE BRACKET */
    { '|', 64 },   /* VERTICAL LINE */
    { 0, 0 },   /* EURO SIGN */
    { 0   , 0      }

};

static int asciChar_to_gsm7int(char c){
 int i;
 
 for(i=0; i<128; i++){
   if (gsm7[i] == c)
     return i;
 }
 
 for(i=0; i<11; i++){
   if (gsm_escape[i].from == c)
   {
     return(gsm_escape[i].to+128*27);
   }
 }
 
 return 63; //question mark
}

static int max127_to_7bitBinaryString(int c, char **binaryString)
{
  int i;
  
  if ((c > 127) || (c < 0))
    return 1;
  
  (*binaryString) = (char *) malloc((8*sizeof(char)));
  (*binaryString)[7] = '\0';
  for(i=6; i>=0; i--)
  {
    (*binaryString)[i] = (c%2 == 1 ? '1': '0');
    c = c/2;
  }
  return 0;
}

static int max16383_to_14bitBinaryString(int c, char **binaryString){
  int i;
  
  if ((c > 16383) || (c < 0))
    return 1;
 
  *binaryString = (char *) malloc(15*sizeof(char));
  (*binaryString)[14] = '\0';
  for(i=13; i>=0; i--)
  {
    (*binaryString)[i] = (c%2 == 1 ? '1': '0');
    c = c/2;
  }
  return 0;
  
}

static int bin8_to_2HexString(char *binaryString, char **hex2String){
  int pom = 0;
  if (strlen(binaryString) != 8)
  {
    (*hex2String) = NULL;
    return 1;
  }
  (*hex2String) = (char *) malloc(3*sizeof(char));
  pom = (binaryString[0]-48)*8 +
        (binaryString[1]-48)*4 + 
	(binaryString[2]-48)*2 + 
	(binaryString[3]-48);
  sprintf((*hex2String), "%1X", pom);
  pom = (binaryString[4]-48)*8 + 
	(binaryString[5]-48)*4 + 
	(binaryString[6]-48)*2 +
	(binaryString[7]-48);
  sprintf(((*hex2String)+1), "%1X", pom);
  return 0;  
}

static int asciText_to_PDUtext(char *asci, char **pdu){
  int asci_len = 0;
  char *result;
  char *r_driver;
  char *gsm7_binnary;
  char *driver;
  char *gsm7B;
  int gsm7B_len;
  char *binaryString;
  char *hex2String;
  int i, j, c, zv;
  
  if ((asci == NULL) || (asci[0] == '\0'))
  {
    *pdu = malloc(sizeof(char));
    (*pdu)[0] = '\0';
    return 0;
  }
  
  asci_len = strlen(asci);
  gsm7_binnary = (char *) malloc((asci_len*14+8)*sizeof(char));
  driver = gsm7_binnary; // urcuje aktualnu poziciu kam zapisujeme v gsm7_binnary
  result = (char *) malloc((asci_len*4+1)*sizeof(char));
   
  for(i=(asci_len-1); i>=0; i--){
    c = asciChar_to_gsm7int(asci[i]);
    if (c <= 127)
    {
      
      max127_to_7bitBinaryString(c, &binaryString);
      //printf("%d: asci:%d gsm7:%d binary:%s\n", i, asci[i], c, binaryString);
      strncpy(driver, binaryString, 8);
      free(binaryString);
      driver = driver + 7*sizeof(char);
    }
    else
    {
      max16383_to_14bitBinaryString(c, &binaryString);
      strncpy(driver, binaryString, 15);
      //printf("%d: asci:%d gsm7:%d binary:%s\n", i, asci[i], c, binaryString);
      free(binaryString);
      driver = driver + 14*sizeof(char);
    }
  }
 
  printf("gsm7_binnary:%s\n", gsm7_binnary);
  gsm7B_len = strlen(gsm7_binnary);
  zv = gsm7B_len%8;
  
  driver = gsm7_binnary + (gsm7B_len-1)*sizeof(char);
  r_driver = result;
  j = gsm7B_len/8;
  r_driver[0] = '\0';
  for(i=0; i<j; i++){
    binaryString = (char *) malloc(9*sizeof(char));
    binaryString = strncpy(binaryString, (driver-7), 8);
    bin8_to_2HexString(binaryString, &hex2String);
    r_driver = strncpy(r_driver, hex2String, 3);   
    driver -= 8;
    r_driver +=2;
    r_driver[0] = '\0';
    free(binaryString);
  }
  
  if (zv>0)
  {
    printf("zvysok:%d\n", zv);
    binaryString = (char *) malloc(9*sizeof(char));
  
    for(i=0; i<(8-zv); i++)
      binaryString[i]='0';
     
    driver = binaryString +(8-zv)*sizeof(char);
     
    driver = strncpy(driver, gsm7_binnary, (zv+1));
    
    binaryString[8] = '\0';
    printf("binaryString:%s\n", binaryString);
    bin8_to_2HexString(binaryString, &hex2String);
    
    r_driver = strncpy(r_driver, hex2String, 3); 
    r_driver +=2;
    free(binaryString);
  }
  
  
  r_driver[0] = '\0';
  (*pdu) = strdup(result);
  //printf("pdu=|%s|\n", (*pdu));
  return (strlen(gsm7_binnary)/7);  
}
/*
int main(){
  char *pdutext;
  int number_of_septets;
  
  number_of_septets = asciText_to_PDUtext("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789[][][][][]", &pdutext);
  printf("%s\n", pdutext);
  printf("number_of_septets:%d\n", number_of_septets);
  
  return 0;
}
*/